/*
 * foreach.h
 *
 *  Created on: 2008-8-29
 *      Author: fanliangliang
 */

#ifndef FOREACH_H_
#define FOREACH_H_

#include "config.h"
#include "is_array.h"

BEGIN_NAMESPACE_TOXIC

namespace detail {

	template <typename T>
	struct type_traits {
		typedef typename T::iterator iterator_type;
	};

	template <typename T>
	struct type_traits<const T> {
		typedef typename T::const_iterator iterator_type;
	};

	template <typename T, size_t N>
	struct type_traits<T[N]> {
		typedef T* iterator_type;
	};

	template <typename T, size_t N>
	struct type_traits<const T[N]> {
		typedef const T* iterator_type;
	};

	template <typename T>
	inline typename type_traits<T>::iterator_type _begin_iterator(T& x, true_type) {
		return x;
	}

	template <typename T>
	inline typename type_traits<T>::iterator_type _begin_iterator(T& x, false_type) {
		return x.begin();
	}


	template <typename T>
	inline typename type_traits<T>::iterator_type _end_iterator(T& x, true_type) {
		return x + dimension_of(x);
	}

	template <typename T>
	inline typename type_traits<T>::iterator_type _end_iterator(T& x, false_type) {
		return x.end();
	}

	template <typename T>
	inline typename type_traits<T>::iterator_type begin_iterator(T& x) {
		return _begin_iterator(x, typename is_array<T>::type());
	}

	template <typename T>
	inline typename type_traits<T>::iterator_type end_iterator(T& x) {
		return _end_iterator(x, typename is_array<T>::type());
	}

	struct auto_any_base {
		operator bool() const {
			return false;
		}
	};

	template<typename T>
	struct auto_any : auto_any_base {
		auto_any(const T& x)
		:item(x) {
		}

		mutable T item;
	};

	template <typename T>
	inline auto_any<T> make_auto_any(const T& x) {
		return auto_any<T>(x);
	}

	typedef const auto_any_base& auto_any_t;

	template <typename T>
	inline T& auto_any_cast(auto_any_t x) {
		return static_cast<const auto_any<T>&>(x).item;
	}

	template <typename T>
	inline bool done(auto_any_t cur, auto_any_t end, T&) {
		return auto_any_cast<typename type_traits<T>::iterator_type>(cur)
			== auto_any_cast<typename type_traits<T>::iterator_type>(end);
	}

	template <typename T>
	inline void next(auto_any_t cur, T&) {
		++auto_any_cast<typename type_traits<T>::iterator_type>(cur);
	}

	template <typename T>
	inline typename type_traits<T>::iterator_type deref(auto_any_t cur, T&) {
		return auto_any_cast<typename type_traits<T>::iterator_type>(cur);
	}

} // namespace detail

END_NAMESPACE_TOXIC

#define foreach(var, col) \
	if (detail::auto_any_t _cur = detail::make_auto_any(detail::begin_iterator(col))) {} else \
	if (detail::auto_any_t _end = detail::make_auto_any(detail::end_iterator(col))) {} else \
	for (bool _continue = true; \
			  _continue && !detail::done(_cur, _end, col); \
			  _continue ? detail::next(_cur, col) : (void)0) \
		if (_continue = false) {} else \
		for (var = *detail::deref(_cur, col); !_continue; _continue = true)

#endif /* FOREACH_H_ */
